package com.freedom.shiro;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;

import com.freedom.bean.core.SysMenu;
import com.freedom.bean.core.SysRole;
import com.freedom.bean.core.SysUser;
import com.freedom.service.core.SysUserService;
import com.freedom.sys.SessionUtils;
import com.freedom.sys.UserUtils;
import com.freedom.util.sys.CipherUtil;

/**
 * 重写myrealm
 * 
 * @author HGJ
 *
 */
public class MyRealm extends AuthorizingRealm {
	private static final Logger logger = LoggerFactory.getLogger(MyRealm.class);

	@Autowired
	private SysUserService sysUserService;

	/**
	 * 授权信息
	 */
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(
			PrincipalCollection principalCollection) {
		String currentUserName = (String) super.getAvailablePrincipal(principalCollection);
		SimpleAuthorizationInfo simpleAuthorInfo = new SimpleAuthorizationInfo();
		SysUser user = UserUtils.getUser();
		if (user.getLoginName().equals(currentUserName)) {
			// 添加一个角色,不是配置意义上的添加,而是证明该用户拥有admin角色
			/*simpleAuthorInfo.addRole("system");
			simpleAuthorInfo.addRole("admin");*///测试演示使用
			//添加动态角色
			List<SysRole> sysRoles = UserUtils.getSysRoles();
			if(sysRoles.size()!=0){
				for(SysRole sysRole:sysRoles){
					simpleAuthorInfo.addRole(sysRole.getEnname()); //角色名称，英文标识
					logger.info("已为用户["+user.getLoginName()+"]赋予了["+sysRole.getEnname()+"]角色标识！");
				}
			}
			// 添加权限，测试数据
			/*simpleAuthorInfo.addStringPermission("admin:edit");
			simpleAuthorInfo.addStringPermission("admin:view");
			simpleAuthorInfo.addStringPermission("admin:dele");
			simpleAuthorInfo.addStringPermission("admin:update");
			System.out.println("已为用户[admin]赋予了[admin]角色和[admin:edit],[admin:dele],[admin:update],[admin:view]权限");*/
			// 添加动态权限标识
			List<SysMenu> sysMenus = UserUtils.getSysMenus();
			if(sysMenus.size()!=0){
				for(SysMenu sysMenu:sysMenus){
					if(!org.apache.commons.lang3.StringUtils.isEmpty(sysMenu.getPermission())){
						simpleAuthorInfo.addStringPermission(sysMenu.getPermission());
						logger.info("已为用户["+user.getLoginName()+"]赋予了["+sysMenu.getPermission()+"]标识权限！");
					}
				}
			}
			return simpleAuthorInfo;
		}
		return null;
	}

	/**
	 * 认证信息
	 */
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(
			AuthenticationToken authcToken) throws AuthenticationException {
		// 实际上这个authcToken是从LoginController里面currentUser.login(token)传过来的
		UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
		SysUser user = sysUserService.checkUserByName(token.getUsername());
		String password = new String((char[])token.getCredentials()); //得到密码
		if (user != null && user.getPassword().equals(password)) {
			AuthenticationInfo authcInfo = new SimpleAuthenticationInfo(user.getLoginName(), CipherUtil.generatePassword(user.getPassword()), getName());
			
			this.setSession("currentUser", user); //当前用户
			List<SysRole> sysUserRoles = UserUtils.getSysRoles();
			this.setSession("sysUserRoles", sysUserRoles); //当前的角色
			
			logger.info("验证当前Subject时获取到token为"
					+ ReflectionToStringBuilder.toString(token,
							ToStringStyle.MULTI_LINE_STYLE));
			return authcInfo;
		}
		return null;
	}

	/**
	 * 将一些数据放到ShiroSession中,以便于其它地方使用
	 * 
	 * @see 比如Controller,使用时直接用HttpSession.getAttribute(key)就可以取到
	 */
	private void setSession(Object key, Object value) {
		Subject currentUser = SecurityUtils.getSubject();
		if (null != currentUser) {
			Session session = currentUser.getSession();
			System.out.println("Session默认超时时间为[" + session.getTimeout() + "]毫秒");
			if (null != session) {
				session.setAttribute(key, value);
			}
		}
	}

	/**
	 * 重写此方法并验证全部所经过的url地址
	 */
	// @SuppressWarnings("unused")
	// @Override
	// public boolean isPermitted(PrincipalCollection principals, String
	// permission) {
	// System.out.println("请求地址：" + permission);
	// List<String> permissionUrl = new ArrayList<String>();
	// String username = (String) principals.getPrimaryPrincipal();
	// if (!StringUtils.isEmpty(username)) {
	// // 实际数据库动态业务逻辑查询获取url地址
	// /*
	// * List<permission> permis = otherService.getURLs(username);
	// * if(null!=permis){ for(Permission p : permis){
	// * //Permission实际是个数据库权限类 permissionUrl.add(p.getPathUrl); } return
	// * this.checkUrl(permissionUrl,permission); }else{ return false; }
	// */
	// List<String> permis = new ArrayList<String>();
	// permis.add("/w/abc");
	// permis.add("/w/abd");
	// permis.add("/w/qwe");
	// // 测试数据地址
	// permis.add("/w/wh001/init");
	// permis.add("/w/wh001/testList1");
	// permis.add("admin:edit");
	// permis.add("admin:dele");
	// permis.add("system:list");
	// if (null != permis) {
	// for (String p : permis) {
	// permissionUrl.add(p);
	// }
	// return this.checkUrl(permissionUrl, permission);
	// } else {
	// return false;
	// }
	// } else {
	// return false;
	// }
	// }

	/**
	 * 校验url
	 * 
	 * @param list
	 * @param url
	 * @return
	 */
	private boolean checkUrl(List<?> listUrl, String url) {
		for (Object list : listUrl) {
			if (list.equals(url)) {
				return true;
			}
		}
		return false;
	}

	/**
	 * 清除所有用户授权信息缓存
	 */
	public void clearCachedAuthorizationInfo(String principal) {
		SimplePrincipalCollection principals = new SimplePrincipalCollection(
				principal, getName());
		clearCachedAuthorizationInfo(principals);
	}

	/**
	 * 清除所有用户授权信息缓存
	 */
	public void clearAllCachedAuthorizationInfo() {
		Cache<Object, AuthorizationInfo> cache = getAuthorizationCache();
		if (cache != null) {
			for (Object key : cache.keys())
				cache.remove(key);
		}
	}

}
